package reson

import (
	log "code.google.com/p/log4go"
	"EasyReson/sqls"
	"EasyReson/global"
	"database/sql"
	"fmt"
	"EasyReson/express-parser"
	"EasyReson/util"
	"strings"
)
/**
	获取源勾兑数据集列表
 */
func GetSrcResult(src1 *global.DbSrc,src2 *global.DbSrc,db1 *sql.DB,db2 *sql.DB,taskId string,taskName string) ([]map[string]interface{},[]map[string]interface{}){

	srcSql1 := buildSrcSql(src1)
	srcSql2 := buildSrcSql(src2)
	log.Info("taskId [%s] taskName [%s] [%s] query Sql1 [%s] ; Sql2 [%s]",taskId,
		taskName,"db1-src",srcSql1,srcSql2)
	src1Results,err := sqls.GetList(srcSql1,db1)
	src2Results,err := sqls.GetList(srcSql2,db2)
	if err!= nil {
		errStr := fmt.Sprintf("taskId [%s] taskName [%s] query Error [%s]",
			taskId,taskName,err)
		log.Error(errStr)
		return make([]map[string]interface{},0),make([]map[string]interface{},0)
	}
	return src1Results,src2Results
}

/**
	建立sql语句
 */
func buildSrcSql(dbSrc *global.DbSrc) string{
	column :="*"
	if ""!= dbSrc.Column {
		column =dbSrc.Column
	}
	return fmt.Sprintf("select %s from %s where %s",column,dbSrc.Table,dbSrc.Condition)
}

/**
	勾兑成功的数据，进行业务状态回写
	reWrite，需要进行回写的字段
	db 执行的数据库，
	data，勾兑成功一条数据记录
	taskName是任务名称,打印时使用
 */
func ExcuseSuccessReWriteSql(taskName string,src *global.DbSrc, db *sql.DB, data map[string]interface{}) {
	reWrite := src.SuccessReWrite
	if len(reWrite)<=0 {
		return
	}
	sqlStr,param := buildSuccessRewriteSql(src,data)
	affected,err := sqls.ExecSql(sqlStr,db,param)

	if err != nil {
		log.Info("taskName:[%s] ResonSuccess reWriteSql:[%s] params [%s] rowAffected [%v] err [%s]",
			taskName,sqlStr,param,affected,err)
	}else if affected<=0 {
		log.Info("taskName:[%s] ResonSuccess reWriteSql:[%s] params [%s] rowAffected [%v]",
			taskName,sqlStr,param,affected)
	}
}
/**
	构造勾兑成功后，对单条记录的uodate语句
 */
func buildSuccessRewriteSql(src *global.DbSrc, data map[string]interface{}) (string,[]interface{}) {

	//获取主键的值
	var keyValue string
	for k,v := range data{
		if util.ToLowerCase(src.Key)==util.ToLowerCase(k){
			keyValue=util.ToString(v)
			break
		}
	}
	/**
		构造sql update条件
	 */
	params := make([]interface{},0)
	condition := ""
	for k,v := range src.SuccessReWrite{
		result :=util.ToString(express_parser.ParserScript(v))
		condition=condition+fmt.Sprintf("%s=?,",k)
		params = append(params, result)
	}
	condition=condition[0:len(condition)-1]

	return fmt.Sprintf("update %s set %s where %s=%s",
		src.Table,condition,src.Key,keyValue),params
}



/**
	勾兑失败的数据，进行业务状态回写
	reWrite，需要进行回写的字段
	db 执行的数据库，
	data，勾兑失败一条数据记录
	taskName是任务名称,打印时使用
 */
func ExcuseFailReWriteSql(taskName string,src *global.DbSrc, db *sql.DB, data map[string]interface{}) {
	reWrite := src.FailReWrite
	if len(reWrite)<=0 {
		return
	}
	sqlStr,param := buildFailRewriteSql(src,data)
	affected,err := sqls.ExecSql(sqlStr,db,param)

	if err != nil {
		log.Info("taskName:[%s] ResonFail reWriteSql:[%s] params [%s] rowAffected [%v] err [%s]",
			taskName,sqlStr,param,affected,err)
	}else if affected<=0 {
		log.Info("taskName:[%s] ResonFail reWriteSql:[%s] params [%s] rowAffected [%v]",
			taskName,sqlStr,param,affected)
	}
}
/**
	构造勾兑失败后，对单条记录的uodate语句
 */
func buildFailRewriteSql(src *global.DbSrc, data map[string]interface{}) (string,[]interface{}) {

	//获取主键的值
	var keyValue string
	for k,v := range data{
		if util.ToLowerCase(src.Key)==util.ToLowerCase(k){
			keyValue=util.ToString(v)
			break
		}
	}
	/**
		构造sql update条件
	 */
	params := make([]interface{},0)
	condition := ""
	for k,v := range src.FailReWrite{
		result :=util.ToString(express_parser.ParserScript(v))
		condition=condition+fmt.Sprintf("%s=?,",k)
		params = append(params, result)
	}
	condition=condition[0:len(condition)-1]

	return fmt.Sprintf("update %s set %s where %s=%s",
		src.Table,condition,src.Key,keyValue),params
}

/**
	将勾兑失败的数据存储到目标差异库db_dest
	columnMapping 列的映射，表示 column要存储的列和src数据库的列的映射，支持时间表达式和原样输出
	data 勾兑失败的数据集
	tableName dbdest存储勾兑失败的数据的表名
	column dbdest数据库中表tableName的列
	db 数据源
 */
func InsertFailIntoDbDest(columnMapping map[string]string,data map[string]interface{}, tableName string, column []string, db *sql.DB) {

	sqlStr,param := buildInsertSql(columnMapping,data,tableName,column)
	_,err := sqls.ExecSql(sqlStr,db,param)
	if err!= nil {
		log.Info("tableName [%s] sql [%s] param [%s] err [%s]",
			tableName,sqlStr,param,err)
	}
}

/**
	构建 勾兑失败时，入库的sql语句
 */
func buildInsertSql(mapping map[string]string, data map[string]interface{}, table string, column []string) (string,[]interface{}) {

	//将mapping的列key转小写备用
	mappingToLower := make(map[string]string)
	for k,v := range mapping {
		mappingToLower[util.ToLowerCase(k)]=v
	}
	//将数据集的key全部转小写备用
	dataToLower := make(map[string]interface{})
	for k,v:= range data {
		dataToLower[util.ToLowerCase(k)]=v
	}

	//列，逗号隔开
	columnStr:=""
	//值占位符，多个问号
	valuePlaceholder:=""
	//值列表
	param := make([]interface{},0)
	for i := range column {
		columnStr=columnStr+column[i]+","
		valuePlaceholder=valuePlaceholder+"?,"
		express := mappingToLower[util.ToLowerCase(column[i])]

		cell :=  express_parser.ParserScript(express)

		//如果express 包含${ 代表它是一个列的占位符，去data里面找到对应的数据，否则，则是时间表达式或者原样输出的值。
		if strings.Contains(express,"${"){
			param=append(param,dataToLower[util.ToLowerCase(cell)])
		}else{
			param=append(param,cell)
		}
	}
	columnStr=columnStr[0:len(columnStr)-1]
	valuePlaceholder=valuePlaceholder[0:len(valuePlaceholder)-1]

	sqlStr := fmt.Sprintf("insert into %s(%s) values(%s)",
	table,columnStr,valuePlaceholder)

	return sqlStr,param
}
